#include "NodeInternal.h"
#include "../../Commons/Utils.h"
using namespace Tree;
using namespace Commons;

NodeInternal::NodeInternal() :
	Node() {

}

/* Adds the node identifier and the first key in the Internal node.
 * Updates the left and rights references (if they exists)
 * RecordToAdd info: nodeOverflowed | firstNodekey | newBrother
 */
void NodeInternal::addInNode(RecordNode* recordToAdd) {

	string firstKey = recordToAdd->getKey();
	int nodeNumber = recordToAdd->getRightReference();
	getRecordNodes()->push_back(recordToAdd);
	Utils::sortRecordsByKey(getRecordNodes());

	//update right reference
	for (unsigned int i = 0; i < getRecordNodes()->size(); i++) {

		RecordNode* current = getRecordNodes()->at(i);

		if (current->getKey() > firstKey) {
			current->setLeftReference(nodeNumber);
			break;
		}
	}
}

/* Returns the number of the node with the current key, or -1 if the nodeKey is bigger than all keys
 * in the node.
 */
int NodeInternal::getChildNodeNumber(string nodeKey) {

	int toReturn = -1;

	for (unsigned int i = 0; i < getRecordNodes()->size(); i++) {

		RecordNode* current = getRecordNodes()->at(i);

		if (current->getKey() > nodeKey) {
			toReturn = current->getLeftReference();
			break;
		}
	}

	return toReturn;
}

//IRecordable methods

void NodeInternal::fillEntity(char *buffer, unsigned int bufferSize) {

	stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
	unsigned int nodeLevel = 0;
	unsigned int numberOfElements = 0;

	//write buffer into stringStream
	ss->seekg(0, ios::beg);
	ss->write(buffer, bufferSize);

	//fill level
	ss->read((char*) &nodeLevel, sizeof(int));
	this->setLevel(nodeLevel);

	//fill number of RecordNodes
	ss->read((char*) &numberOfElements, sizeof(int));

	//fill records
	for (unsigned int i = 0; i < numberOfElements; i++) {

		RecordNode* record = new RecordNode(); //Record: key, left ref, right ref
		string key;
		int leftNodeReference = -1;
		int rightNodeReference = -1;

		key = Utils::GetNextStringValue(ss);
		ss->read((char*) &(leftNodeReference), sizeof(int));
		ss->read((char*) &(rightNodeReference), sizeof(int));

		record->setKey(key);
		record->setLeftReference(leftNodeReference);
		record->setRightReference(rightNodeReference);

		this->getRecordNodes()->push_back(record);
	}

}

char* NodeInternal::buildBuffer() {

	stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
	unsigned int nodeLevel = getLevel();
	unsigned int numberOfElements = getRecordNodes()->size();
	unsigned int bufferSize = getBufferSize();
	char* buffer = new char[bufferSize];

	//add header
	ss->seekp(0, ios::end);
	ss->write((char*) &nodeLevel, sizeof(int));
	ss->write((char*) &numberOfElements, sizeof(int));

	//add records
	for (unsigned int i = 0; i < numberOfElements; i++) {

		RecordNode* currentRecord = getRecordNodes()->at(i); //Record: key, left ref, right ref
		int keySize = currentRecord->getKey().size();
		int leftNodeReference = currentRecord->getLeftReference();
		int rightNodeReference = currentRecord->getRightReference();

		ss->write((char*) &keySize, sizeof(int));
		ss->write(currentRecord->getKey().c_str(), currentRecord->getKey().size());
		ss->write((char*) &(leftNodeReference), sizeof(int));
		ss->write((char*) &(rightNodeReference), sizeof(int));
	}

	//build buffer
	ss->read(buffer, bufferSize);

	return buffer;

}

unsigned int NodeInternal::getBufferSize() {

	unsigned int toReturn = (sizeof(int) * 3); //header

	for (unsigned int i = 0; i < getRecordNodes()->size(); i++) {
		//Record: key, left ref, right ref
		RecordNode* currentRecord = getRecordNodes()->at(i);
		toReturn += sizeof(int) + currentRecord->getKey().size();
		toReturn += sizeof(int) * 2;
	}

	return toReturn;
}

NodeInternal::~NodeInternal() {

}
